package com.tcm.controller.front;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
import com.tcm.common.enums.ResponseEnum;
import com.tcm.config.AppProperties;
import com.tcm.config.WechatMiniAppConfig;
import com.tcm.entity.User;
import com.tcm.entity.dto.param.UserLoginParam;
import com.tcm.entity.dto.param.UserLoginWxParam;
import com.tcm.entity.resp.R;
import com.tcm.exception.UserNotExistException;
import com.tcm.exception.UserTypeNotInvalidException;
import com.tcm.exception.WxUserNotBindException;
import com.tcm.service.AuthService;
import com.tcm.utils.AccessTokenUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Map;

/**
 * 学生权限验证控制器
 * @author Guqier
 * @version 1.0
 * @date 2023/7/11 16:12
 */
@Slf4j
@RestController
@RequestMapping("/stu/auth")
public class StuAuthController {

    @Autowired
    private WechatMiniAppConfig wechatMiniAppConfig;

    @Autowired
    private AuthService authService;

    /**
     * 微信用户登录
     * @param param 登录参数
     * @return 登录响应结果
     */
    @RequestMapping(value = "/wxLogin", method = RequestMethod.POST)
    public R wxLogin(@RequestBody UserLoginWxParam param){
        // code不为空
        if (!StringUtils.hasText(param.getCode())) {
            return R.fail(ResponseEnum.CODE_EMPTY);
        }
        WxMaService wxMaService = new WxMaServiceImpl();
        WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaDefaultConfigImpl();
        wxMaDefaultConfig.setAppid(wechatMiniAppConfig.getAppid());
        wxMaDefaultConfig.setSecret(wechatMiniAppConfig.getAppsecret());
        wxMaService.setWxMaConfig(wxMaDefaultConfig);
        try {
            // 获取微信用户信息
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(param.getCode());
            // 执行登录
            Map<String, String> result = authService.wxLogin(session, AppProperties.FRONT_LOGIN_ALLOW_USER_TYPE);
            result.put("session_key", session.getSessionKey());
            return R.success(result);
        } catch (WxErrorException e){
            return R.fail(ResponseEnum.WX_ERROR);
        } catch (WxUserNotBindException e) {
            return R.fail(ResponseEnum.WX_USER_NEED_BIND);
        }
    }

    /**
     * 通用学生用户登录
     * @param param 登录参数
     * @return token
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public R login(@RequestBody @Valid UserLoginWxParam param){
        User user = new User();
        user.setAccount(param.getAccount());
        user.setPassword(param.getPassword());
        Map<String, String> resMap = null;
        try {
            resMap = authService.login(user, AppProperties.FRONT_LOGIN_ALLOW_USER_TYPE);
        }catch (UserNotExistException e){
            return R.fail(ResponseEnum.USER_LOGIN_ERROR);// 用户不存在
        }catch (UserTypeNotInvalidException e){
            return R.fail(205, e.getMessage());// 该账户类型未被允许
        }
        if (resMap == null) {
            return R.fail(ResponseEnum.USER_LOGIN_ERROR);// 账号或密码错误
        }
        return R.success(resMap);
    }

    /**
     * 学生用户登出
     * @param request 请求对象
     * @return 登出结果
     */
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    public R logout(HttpServletRequest request){
        if (authService.logout(AccessTokenUtil.getAccessToken(request))) {
            return R.success();
        }else {
            return R.fail(ResponseEnum.USER_NOT_LOGIN);
        }
    }

    /**
     * 刷新AccessToken
     * @param request http请求对象
     * @return 刷新后的token
     */
    @RequestMapping(value = "/refresh", method = RequestMethod.GET)
    public R refreshToken(HttpServletRequest request){
        Long userId = AccessTokenUtil.getUserId(request);
        String account = AccessTokenUtil.getUserAccount(request);
        log.info("刷新Token：{}", userId);
        Map<String, String> map = authService.refreshToken(userId, account, AccessTokenUtil.getAccessToken(request));
        return R.success(map);
    }

    /**
     * 绑定微信账号
     * @param param code码
     * @param request 请求对象
     * @return 绑定结果
     */
    @RequestMapping(value = "/wx/bind", method = RequestMethod.POST)
    public R miniAppAccountBind(@RequestBody UserLoginWxParam param, HttpServletRequest request){
        Long userId = AccessTokenUtil.getUserId(request);
        String code = param.getCode();
        if (!StringUtils.hasText(code)) {
            return R.fail(ResponseEnum.CODE_EMPTY);
        }
        WxMaService wxMaService = new WxMaServiceImpl();
        WxMaDefaultConfigImpl wxMaDefaultConfig = new WxMaDefaultConfigImpl();
        wxMaDefaultConfig.setAppid(wechatMiniAppConfig.getAppid());
        wxMaDefaultConfig.setSecret(wechatMiniAppConfig.getAppsecret());
        wxMaService.setWxMaConfig(wxMaDefaultConfig);
        try {
            // 获取微信用户信息
            WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(param.getCode());
            // 执行绑定
            boolean b = authService.miniAppBind(session.getOpenid(), userId);
            return b ? R.success() : R.fail(ResponseEnum.DATABASE_OPERATION_FAIL);
        } catch (WxErrorException e){
            return R.fail(ResponseEnum.WX_ERROR);
        }
    }

    /**
     * 学生PC端登录
     * @param param 学生登录参数
     * @return 登录结果
     */
    @RequestMapping(value = "/pc/login", method = RequestMethod.POST)
    public R loginWithCaptcha(@RequestBody UserLoginParam param){
        String code = param.getCode();
        if (!authService.verifyAuthCode(param.getUuid(), code)) {
            return R.fail(ResponseEnum.ERROR_AUTH_CODE);
        }
        User user = new User();
        BeanUtils.copyProperties(param, user, "code");
        Map<String, String> resMap = null;
        try {
            resMap = authService.login(user, AppProperties.FRONT_LOGIN_ALLOW_USER_TYPE);
        }catch (UserNotExistException e){
            return R.fail(ResponseEnum.USER_LOGIN_ERROR);// 用户不存在
        }catch (UserTypeNotInvalidException e){
            return R.fail(205, e.getMessage());// 学生登录禁止
        }
        if (resMap == null) {
            return R.fail(ResponseEnum.USER_LOGIN_ERROR);// 账号或密码错误
        }
        return R.success(resMap);
    }

    /**
     * 获取登录验证码
     * @return 正常情况响应为null
     */
    @RequestMapping(value = "/pc/code", method = RequestMethod.GET)
    public R authCode(){
        return R.success(authService.generateAuthCode());
    }

    /**
     * 解绑微信账号
     * @param request 请求对象
     * @return 处理结果
     */
    @RequestMapping(value = "/wx/bind", method = RequestMethod.DELETE)
    public R removeWxBind(HttpServletRequest request){
        return authService.miniAppUnbind(AccessTokenUtil.getUserId(request)) ? R.success() : R.fail(ResponseEnum.DATABASE_OPERATION_FAIL);
    }
}
